﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sealight.API.Ioc;
using Sealight.CoreAPI;
using Sealight.API.Framework.Caching;

namespace Sealight.Bussiness
{   
    /// <summary>
    /// cache manager
    /// </summary>
    public static class CacheManager
    {
        volatile static IDictionary<string, IList<string>> cacheGroup = new Dictionary<string, IList<string>>();
        const string GroupKey = "__GroupName:{0}__Key:{1}__";
        /// <summary>
        /// cache provider
        /// </summary>
        static volatile IEntlibCacheService cacheProvider = null;
        static object lockHelper = new object();
        /// <summary>
        /// Gets the cache provider.
        /// </summary>
        /// <value>The cache provider.</value>
        public static IEntlibCacheService CacheProvider
        {
            get
            {
                if (cacheProvider == null)
                {
                    lock (lockHelper)
                    {
                        if (cacheProvider == null)
                        {
                            cacheProvider = IocContainer.Container().Resolve<IEntlibCacheService>();
                        }
                    }
                }
                return cacheProvider;
            }
        }

        /// <summary>
        /// Adds new CacheItem to cache.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        public static void Add(string key, object value)
        {
            CacheProvider.Add(key, value);
        }
        /// <summary>
        /// Adds the specified group name.
        /// </summary>
        /// <param name="groupName">Name of the group.</param>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        public static void Add(string groupName, string key, object value)
        {
            string cacheKey = GetCacheKey(groupName, key);
            AddToGroup(groupName, key);
            Add(cacheKey, value);
        }

        private static void AddToGroup(string groupName, string key)
        {
            if (!cacheGroup.ContainsKey(groupName))
            {
                lock (lockHelper)
                {
                    if (!cacheGroup.ContainsKey(groupName))
                    {
                        cacheGroup.Add(groupName, new List<string>());
                    }
                }
            }
            IList<string> keyList = cacheGroup[groupName];
            lock (lockHelper)
            {
                if (!keyList.Contains(key))
                {
                    keyList.Add(key);
                }
            }
        }
        public static string GetCacheKey(string groupName, string key)
        {
            return string.Format(GroupKey, groupName, key);
        }
        /// <summary>
        /// Adds new CacheItem to cache.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <param name="priority">The priority.</param>
        /// <param name="refreshAction">The refresh action.</param>
        /// <param name="expirations">The expirations.</param>
        public static void Add(string key, object value, CacheItemPriority priority, ICacheItemRefreshAction refreshAction, params ICacheItemExpiration[] expirations)
        {
            CacheProvider.Add(key, value, priority, refreshAction, expirations);
        }
        /// <summary>
        /// Adds the specified group name.
        /// </summary>
        /// <param name="groupName">Name of the group.</param>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <param name="priority">The priority.</param>
        /// <param name="refreshAction">The refresh action.</param>
        /// <param name="expirations">The expirations.</param>
        public static void Add(string groupName, string key, object value, CacheItemPriority priority, ICacheItemRefreshAction refreshAction, params ICacheItemExpiration[] expirations)
        {
            string cacheKey = GetCacheKey(groupName, key);
            AddToGroup(groupName, key);

            Add(cacheKey, value, priority, refreshAction, expirations);
        }
        /// <summary>
        /// Returns true if key refers to item current stored in cache
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>
        /// 	<c>true</c> if [contains] [the specified key]; otherwise, <c>false</c>.
        /// </returns>
        public static bool Contains(string key)
        {
            return CacheProvider.Contains(key);
        }
        /// <summary>
        /// Returns the number of items currently in the cache.
        /// </summary>
        /// <value>The count.</value>
        public static int Count
        {
            get { return CacheProvider.Count; }
        }

        /// <summary>
        /// Removes all items from the cache.
        /// </summary>
        public static void Flush()
        {
            CacheProvider.Flush();
        }
        /// <summary>
        /// Returns the value associated with the given key.
        /// </summary>
        /// <returns></returns>
        public static object Get(string key)
        {
            return CacheProvider.Get(key);
        }

        /// <summary>
        /// Gets the specified group name.
        /// </summary>
        /// <param name="groupName">Name of the group.</param>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static object Get(string groupName, string key)
        {
            string cacheKey = GetCacheKey(groupName, key);
            return Get(cacheKey);
        }

        /// <summary>
        /// Removes the given item from the cache. If no item exists with that key, this method does nothing.
        /// </summary>
        /// <param name="key">The key.</param>
        public static void Remove(string key)
        {
            CacheProvider.Remove(key);
        }

        /// <summary>
        /// Removes the cache group.
        /// </summary>
        /// <param name="groupName">Name of the group.</param>
        public static void RemoveCacheGroup(string groupName)
        {
            if (cacheGroup.ContainsKey(groupName))
            {
                IList<string> keyList = cacheGroup[groupName];
                if (keyList != null)
                {
                    lock (lockHelper)
                    {
                        while (keyList.Count > 0)
                        {
                            string key = keyList.First();
                            Remove(GetCacheKey(groupName, key));
                            keyList.Remove(key);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Removes the cache groups.
        /// </summary>
        /// <param name="groups">The groups.</param>
        public static void RemoveCacheGroups(IEnumerable<string> groups)
        {
            foreach (var group in groups)
            {
                RemoveCacheGroup(group);
            }
        }
        /// <summary>
        /// Removes the specified group name.
        /// </summary>
        /// <param name="groupName">Name of the group.</param>
        /// <param name="key">The key.</param>
        public static void Remove(string groupName, string key)
        {
            Remove(GetCacheKey(groupName, key));
        }

        /// <summary>
        /// Removes all groups.
        /// </summary>
        public static void RemoveAllGroups()
        {
            RemoveCacheGroups(cacheGroup.Keys);
        }

        /// <summary>
        /// Gets the data by the specified key.
        /// if data not in cache,use dataFunc to get data and store into cache.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">The key.</param>
        /// <param name="dataFunc">The data func.</param>
        /// <param name="expirations">The expirations.</param>
        /// <returns></returns>
        public static T Get<T>(object lockHelper, string key, Func<T> dataFunc, CacheItemPriority priority, ICacheItemRefreshAction refreshAction, params ICacheItemExpiration[] expirations)
            where T : class
        {
            T data = CacheManager.Get(key) as T;
            if (data == null)
            {
                lock (lockHelper)
                {
                    if (CacheManager.Get(key) as T == null)
                    {
                        data = dataFunc();
                        CacheManager.Add(key, data, priority, refreshAction, expirations);
                    }
                }
            }
            return data;

        }
    }
}

